#pragma once

#include "EntityTable.h"
#include "Utilities.h"

EntityTable::EntityTable(void){
	lineEntityTable = LineEntityTableType();
	lineTable =  LineTableType();
}

EntityTable::~EntityTable(void){
	clear();
}

void EntityTable::clear(){
	lineEntityTable.clear();
	lineTable.clear();
}

bool EntityTable::insertLineEntity(Type::Index::Line line, Type::Entity::Line entity){

	// invalid line index or entity or line alreayd exist in the table
	if(!Utilities::isValidLineIndex(line) || !Utilities::isValidLineEntity(entity) 
		|| isLineExistsInEntity(line)){
			return false;
	}

	Type::List::Line lineEntityList;
	Type::List::Line allLineList;
	Type::List::Line lineList;
	Type::Entity::Line allLineType = Type::Entity::ALL_LINE_ENTITY;

	if(isEntityExistsInLine(entity)){
		lineList = lineTable.at(entity);
		lineTable.erase(entity);
	}

	if(isEntityExistsInLine(allLineType)){
		allLineList = lineTable.at(allLineType);
		lineTable.erase(allLineType);
	}

	/*******************lineTable**********************/
	if(!Utilities::isExistInList(lineList, line)){
		lineList.push_back(line);
	}
	lineTable.insert(std::make_pair<Type::Entity::Line, Type::List::Line>(entity, lineList));

	if(!Utilities::isExistInList(allLineList, line)){
		allLineList.push_back(line);
	}
	lineTable.insert(std::make_pair<Type::Entity::Line, Type::List::Line>(allLineType, allLineList));

	/*******************entityTable**********************/
	lineEntityTable.insert(std::make_pair<Type::Index::Line, Type::Entity::Line>(line, entity));

	return true;
}

// get all entities
const Type::List::LineEntity& EntityTable::getLineEntities(){
	Type::List::LineEntity* list = new Type::List::LineEntity();

	if(lineTable.size() > 0){
		for(LineTableType::iterator it=lineTable.begin(); it != lineTable.end(); it++){
			if(it->first != Type::Entity::ALL_LINE_ENTITY){
				list->push_back(it->first);
			}
		}
	}

	return *list;
}

// get entity with the given line
Type::Entity::Line EntityTable::getLineEntityByLine(Type::Index::Line line){

	if(Utilities::isValidLineIndex(line) && isLineExistsInEntity(line)){
		return lineEntityTable.at(line);
	}else{
		return Type::Entity::INVALID_LINE_ENTITY;
	}
}

// get the list of all lines
const Type::List::Line& EntityTable::getLines(){
	return getLinesByEntity(Type::Entity::ALL_LINE_ENTITY);
}

// get the list of lines associated with the given entity
const Type::List::Line& EntityTable::getLinesByEntity(Type::Entity::Line entity){
	if(Utilities::isValidLineEntity(entity) && isEntityExistsInLine(entity)){
		return lineTable.at(entity);
	}

	return *(new Type::List::Line());
}

/// check if the given line matches with the given line entity
bool EntityTable::isLineEntity(Type::Index::Line line, Type::Entity::Line entity){
	if(!Utilities::isValidLineIndex(line) || !Utilities::isValidLineEntity(entity)
		|| !isLineExistsInEntity(line) || !isEntityExistsInLine(entity)){
			return false;
	}

	Type::Entity::Line tmpEntity = lineEntityTable.at(line);
	return tmpEntity == entity;
}

// check for exsistence of the given entity
bool EntityTable::isEntityExistsInLine(Type::Entity::Line entity){
	return lineTable.find(entity) != lineTable.end();
}

// check for exsistence of the given line
bool EntityTable::isLineExistsInEntity(Type::Index::Line line){
	return lineEntityTable.find(line) != lineEntityTable.end();
}